#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include "function_interface.h"
#include "TableInterface/upper_table_interface.h"
#include "TableInterface/hmi_table_interface.h"
#include "TableInterface/ems_table_interface.h"
#include "TableInterface/lc_table_interface.h"
#include "TableInterface/bms_table_interface.h"
#include "TableInterface/dcdc_table_interface.h"
#include "TableInterface/misc_table_interface.h"
#include "ErrorLog.h"
#include "utils.h"
#include "global_variable.h"
#include "msg_queue_interface.h"
#include "msg_queue_pid_define.h"
#include <signal.h>
#include <time.h>
#include "debug.h"
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "misc.h"
#include "Commom/timer_interface.h"
#include "syslog.h"
#include <stdbool.h>
#include "Commom/mutex_interface.h"


extern bool glb_FPGA_upgrade_is_running;
extern int TableRefresh_SendMessage(tableMsgVal_t msgVal);
static timer_t timerIdCmd0 = NULL;
static uint16_t stateErrLck[16] = {0};
static uint16_t stateArmFault[3] = {0};


static int TableRefresh_Init(void)
{
    uint16_t idx;

    /* 刚启动完成需要更新一次上位机模式显示 */
    TableRefresh_SendMessage(TABLE_MSGVAL_MODE);

    for(idx = 0; idx < 16; idx++)
    {
        FuncInf_GetFaultRegister(idx, &stateErrLck[idx]);
    }

    return 0;
}


static void TableRefresh_RefreshTable(tableMsgVal_t msgVal)
{
    UpperTable_Refresh(msgVal);
    HmiTable_Refresh(msgVal);
    EmsTable_Refresh(msgVal);
    LcTable_Refresh(msgVal);
    // BmsTable_Refresh(msgVal);
    // DcdcTable_Refresh(msgVal);
    // MiscTable_Refresh(msgVal);
}


int TableRefresh_SetArmFaultState(uint8_t idx, uint16_t state)
{
    if(idx >= 3)
    {
        PRINT_WARN("%d", idx);
        return -1;
    }

    MutexInf_Lock(MUTEX_IDX_ARM_FAULT);
    stateArmFault[idx] = state;
    MutexInf_Unlock(MUTEX_IDX_ARM_FAULT);
    
    return 0;
}
 

static void TableRefresh_UpdateArmFault(void)
{
    u16BitType_t state;
    uint16_t addr;
    uint8_t u8Val;
    
    /* state13 */
    state.u16Data = 0;

    if(state.u16Data != stateArmFault[0])
    {
        TableRefresh_SetArmFaultState(0, state.u16Data);
        addr = FPGA_ADDR_ARM_FAULT_REG_BEGIN + 0;
        if(FuncInf_DirectWriteFpga(FUNCINF_OPERATOR_UPPER, addr, state.u16Data) != FUNCINF_ERR_NONE)
        {
            PRINT_WARN("Address %d Write failure", addr);
        }
    }    

    /* state14 */
    state.u16Data = 0;
    GlobalVariable_GetUint8(GV_UINT8_OIL_TEMP, &u8Val);
    state.bitData.b0 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_OIL_PRES, &u8Val);
    state.bitData.b1 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_OIL_POS, &u8Val);
    state.bitData.b2 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_LOAD_BRK, &u8Val);
    state.bitData.b3 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_SMOKE, &u8Val);
    state.bitData.b4 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_DOOR, &u8Val);
    state.bitData.b5 = u8Val;

    if(state.u16Data != stateArmFault[1])
    {
        TableRefresh_SetArmFaultState(1, state.u16Data);
        addr = FPGA_ADDR_ARM_FAULT_REG_BEGIN + 1;
        if(FuncInf_DirectWriteFpga(FUNCINF_OPERATOR_UPPER, addr, state.u16Data) != FUNCINF_ERR_NONE)
        {
            PRINT_WARN("Address %d Write failure", addr);
        }
    }

    /* state15 */
    state.u16Data = 0;
    
    GlobalVariable_GetUint8(GV_UINT8_3L_OV_A, &u8Val);
    state.bitData.b0 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_3L_UV_A, &u8Val);
    state.bitData.b1 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_3L_OV_B, &u8Val);
    state.bitData.b2 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_3L_UV_B, &u8Val);
    state.bitData.b3 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_3L_OV_C, &u8Val);
    state.bitData.b4 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_3L_UV_C, &u8Val);
    state.bitData.b5 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_CUR_ZERO_AC_A, &u8Val);
    state.bitData.b6 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_CUR_ZERO_AC_B, &u8Val);
    state.bitData.b7 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_CUR_ZERO_AC_C, &u8Val);
    state.bitData.b8 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_CUR_ZERO_DC, &u8Val);
    state.bitData.b9 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_3L_OF, &u8Val);
    state.bitData.b10 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_3L_UF, &u8Val);
    state.bitData.b11 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_OVER_TEMPERATURE, &u8Val);
    state.bitData.b12 = u8Val;
    GlobalVariable_GetUint8(GV_UINT8_OVER_LEAK_CUR, &u8Val);
    state.bitData.b13 = u8Val;

    if(state.u16Data != stateArmFault[2])
    {
        TableRefresh_SetArmFaultState(2, state.u16Data);
        addr = FPGA_ADDR_ARM_FAULT_REG_BEGIN + 2;
        if(FuncInf_DirectWriteFpga(FUNCINF_OPERATOR_UPPER, addr, state.u16Data) != FUNCINF_ERR_NONE)
        {
            PRINT_WARN("Address %d Write failure", addr);
        }
    }
}


static void TableRefresh_GenerateFaultInfo(void)
{
    uint16_t i, idx, state, stateErrLckCur[16] = {0};
    int errorId;

    for(idx = 0; idx < 16; idx++)
    {
        if(idx >= 7 && idx <= 12)
        {
            continue;
        }

        if(FuncInf_GetFaultRegister(idx, &stateErrLckCur[idx]) != 0)
        {
            continue;
        }

        state = stateErrLck[idx] ^ stateErrLckCur[idx];
        // PRINT_DEBUG("idx[%d] state[0x%04X] stateErrLck[0x%04X] stateErrLckCur[0x%04X]", idx, state, stateErrLck[idx], stateErrLckCur[idx]);

        for(i = 0; i < 16; i++)
        {
            if(GET_BIT(state, i))
            {
                errorId = idx * 16 + i;
                errorId = GET_BIT(stateErrLckCur[idx], i) ? errorId + 1 : (-1) * (errorId + 1);
                if(errorId > 256 || errorId < -256)
                {
                    continue;
                } 
                errorMsgSend(errorId);
                if(errorId > 0)
                {
                    PRINT_DEBUG("state%d[%d] errorId[%d]", idx, i, errorId);
                    syslog(LOG_INFO, "%s: state%d[%d] errorId[%d]", __func__, idx, i, errorId);
                }
            }
        }
        
        stateErrLck[idx] = stateErrLckCur[idx];
        // PRINT_DEBUG();
    }
}


static void TableRefresh_HandleSignalCmd0(union sigval arg)
{
    ((void)(arg));
    syslog(LOG_INFO, "%s", __func__);
    if(FuncInf_DirectWriteFpga(FUNCINF_OPERATOR_UPPER, FPGA_ADDR_CMD_BEGIN + 0, 0) != FUNCINF_ERR_NONE)
    {
        PRINT_WARN();
    }
}


static int TableRefresh_ConfirmCmd0Reset(void)
{
    uint16_t cmd = 0;

    if(FuncInf_DirectReadFpga(FPGA_ADDR_CMD_BEGIN + 0, &cmd) != FUNCINF_ERR_NONE)
    {
        PRINT_WARN();
        return -1;
    }

    if(cmd != 0)
    {
        if(TimerInf_Create(&timerIdCmd0, TableRefresh_HandleSignalCmd0, NULL) != 0)
        {
            PRINT_WARN();
            return -2;
        }
        if(TimerInf_Start(timerIdCmd0, 0, 100000000, TIMER_ONCE) != 0)
        {
            PRINT_WARN();
            return -3;
        }
    }

    return 0;
}


void TableRefresh_Thread(void *pPara)
{
    Misc_InitThread(__func__);

    int err, msgId;
    tableMsgVal_t msgVal;
    char msgData[MSG_DATA_LEN] = {0};
    
    if(MsgQueue_Get(MSG_QUEUE_PID_TABLE_REFRESH, &msgId) < 0)
	{
        // PRINT_ERROR("Get error");
		return;
	}

    if(TableRefresh_Init() != 0)
    {
        return;
    }

    while(1)
    {
        if((err = MsgQueue_Recv1(msgId, msgData)) < 0)
        {
            PRINT_ERROR("Recv error[%d]", err);
        }

        if(glb_FPGA_upgrade_is_running == true)
        {
            continue;
        }

        msgVal = (tableMsgVal_t)((msgData[3] << 24) | (msgData[2] << 16) | (msgData[1] << 8) | msgData[0]);
        // PRINT_DEBUG("msgVal[%d]", (uint32_t)msgVal);
        TableRefresh_RefreshTable(msgVal);
        if(msgVal == TABLE_MSGVAL_FPGA)
        {
            TableRefresh_UpdateArmFault();
            TableRefresh_GenerateFaultInfo();
            TableRefresh_ConfirmCmd0Reset();
        }
    }
}


int TableRefresh_SendMessage(tableMsgVal_t msgVal)
{
    int err, msgId;
    char buf[MSG_DATA_LEN] = {0};

    if((err = MsgQueue_Get(MSG_QUEUE_PID_TABLE_REFRESH, &msgId)) < 0)
	{
        // PRINT_WARN("Get error[%d]", err);
		return -1;
	}

    buf[0] = (((uint32_t)msgVal >> 0) & 0xFF);
    buf[1] = (((uint32_t)msgVal >> 8) & 0xFF);
    buf[2] = (((uint32_t)msgVal >> 16) & 0xFF);
    buf[3] = (((uint32_t)msgVal >> 24) & 0xFF);

    if((err = MsgQueue_Send1(msgId, buf)) < 0)
    {
        PRINT_WARN("Send error[%d]", err);
        return -2;
    }

    return 0;
}


int TableRefresh_DeleteTimer(void)
{
    if(TimerInf_Delete(&timerIdCmd0) != 0)
    {
        PRINT_WARN();
        return -1;
    }

    return 0;
}


void TableRefreshAssist_Thread(void *pPara)
{
    Misc_InitThread(__func__);

    uint32_t cnt = 0;

    while(1)
    {
        cnt++;

        /* 500ms */
        if(cnt % 5 == 0)
        {
            TableRefresh_SendMessage(TABLE_MSGVAL_FPGA);
            PRINT_DEBUG("TABLE_MSGVAL_FPGA");
        }
        
        /* 1s */
        if(cnt % 10 == 0)
        {
            TableRefresh_SendMessage(TABLE_MSGVAL_TIME);
            PRINT_DEBUG("TABLE_MSGVAL_TIME");
        }
        
        /* 1min */
        if(cnt % 600 == 0)
        {
            syslog(LOG_DEBUG, "%s", __func__);
        }

        usleep(100000);
    }
}

